/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package jturbofile.net;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import jturbofile.gui.ConnectedUserUI;
import jturbofile.gui.LogPanel;

/**
 *
 * @author Rolf
 */
public class PeerThread implements Runnable {

    private List<Handler> handlers;
    private Socket sock;
    private ObjectInputStream in;
    private ObjectOutputStream out;
    private boolean shouldGoOn;
    private ConnectedUserUI userUI;
    
    public PeerThread(Socket s) {
        this.sock = s;
        shouldGoOn = true;
        handlers = new ArrayList<Handler>();
        
        try {
            out = new ObjectOutputStream( sock .getOutputStream() );
            in = new ObjectInputStream( sock.getInputStream() );
        }
        catch(Exception e) {
            LogPanel.singleton().logln("Error creating streams: "+e);
            shouldGoOn = false;
        }
        
        defaultHandlers();
    }

    public void setConnectedUserUI(ConnectedUserUI ui) {
        userUI = ui;
    }
    
    public ConnectedUserUI getConnectedUserUI() {
        return userUI;
    }
    
    public void close() {
        try {
            shouldGoOn = false;
            sock.close();
            in.close();
            out.close();
        }
        catch(Exception e) {
            LogPanel.singleton().logln("Error closing connection: "+e);
        }
    }

    public void run() {
        try {
            if(shouldGoOn) {
                LogPanel.singleton().logln("PeerThread started for client ["+sock.getInetAddress().getHostAddress()+"]...");

                while(shouldGoOn) {
                    Packet p = (Packet) in.readObject();

                    //LogPanel.singleton().logln("Packet received: "+p.getType());

                    handlePacket(p);
                }
                
                LogPanel.singleton().logln("PeerThread closed for client ["+sock.getInetAddress().getHostAddress()+"]...");
            }
        }
        catch(Exception e) {
            System.out.print("Error in peer communication ["+sock.getInetAddress().getHostAddress()+"]: "+e);
        }
        
        NetCore.singleton().removePeerThread(sock);
    }

    public void addHandler(Handler h) {
        handlers.add(h);
    }

    public String getHostAddress() {
        return sock.getInetAddress().getHostAddress();
    }

    void removeHandler(Handler h) {
        handlers.remove(h);
    }
    
    private void defaultHandlers() {
        this.addHandler(new FileHandler());
        this.addHandler(new CloseHandler());
    }

    private void handlePacket(Packet p) {
        boolean handled = false;
        
        for(Handler h : handlers) {
            if( h.handlePacket(p, this) ) {
                handled = true;
            }
        }
        
        if( !handled ) {
            LogPanel.singleton().logln("Unhandled packet type: ["+p.getType()+"]");
        }
    }
    
    public synchronized boolean sendPacket(Packet p) {
        try {
            p.setSender(sock.getLocalAddress().getHostAddress());
            
            out.writeObject(p);
            out.flush();
            
            return true;
        }
        catch(Exception e) {
            LogPanel.singleton().logln("Error sending packet: "+e);
            
            return false;
        }
    }
    
    @Override
    public String toString() {
        return ""+sock.getInetAddress().getHostAddress();
    }
}
